import { _decorator, Asset, CCBoolean, Component, Enum, Node, Prefab, SpriteFrame, Texture2D, tween, UIOpacityComponent, UITransform, v3 } from "cc";
import { UIID } from "../../game/config/Config";
import { OrderLayer } from "../config/Appcfg";
import { EventMgr } from "../manager/EventMgr";
import { ResCacheMgr } from "../manager/ResCacheMgr";
import { CompleteCallback, ResCacheKey, ResourceMgr } from "../manager/ResourceMgr";
import { TweenMgr } from "../manager/TweenMgr";
import { UIMgr } from "../manager/UIMgr";
import { ArgsParseUtils, LoadResArgs, LoadSpriteFrameArgs } from "../utils/ArgsParseUtils";
const { ccclass, property } = _decorator;
export enum OpenAin {
    None,
    Pop,
}
Enum(OpenAin)
@ccclass('BaseUI')
export class BaseUI extends Component {
    @property({ type: CCBoolean, tooltip: "是否缓存", displayName: "是否缓存" })
    cache: boolean = false;
    @property({ type: OpenAin, tooltip: "注意：主节点下只需bg 和 root", displayName: "打开动画" })
    openAniType: OpenAin = OpenAin.None;

    public layer: OrderLayer
    private uid: number = -1;
    private resArray: ResCacheKey[] = []
    public fromId: UIID;
    private eventList: Array<Map<string, Function>> = new Array();
    protected isclose: boolean = false;
    private _findChilds = new Map<string,Node>();
    /**参数 */
    public param:any;
    findChilds(name:string,node?:Node):Node{
        node = node || this.node;
        if(this._findChilds.has(name)){
            return this._findChilds.get(name);
        }
        //写一个递归查找节点
        for(let i = 0; i < node.children.length; i++){
            if(node.children[i].name === name){
                this._findChilds.set(name,node.children[i]);
                return node.children[i];
            }else{
                const foundNode = this.findChilds(name, node.children[i]);
                if (foundNode) {
                    return foundNode;
                }
            }
        }
    }
    /**
     * 添加监听的事件
     * @param listenename 事件名
     * @param fun 响应的方法
     */
    protected addEvent(listenename: string, fun: Function) {
        EventMgr.getInstance().on(listenename, this, fun);
        let map: Map<string, Function> = new Map();
        map.set(listenename, fun);
        this.eventList.push(map);
    }
    refreshUI(uid, fromId, callback, param1, param2, param3, param4, param5) {

    }
    public init(param1?: any, param2?: any, param3?: any, param4?: any, param5?: any) {
        this.isclose = false;
    }
    /**
     * 发送事件
     * @param listenerName 事件名称
     * @param param1 
     * @param param2 
     * @param param3 
     * @param param4 
     * @param param5 
     */
    protected sendEvent(listenerName: string, param1?: any, param2?: any, param3?: any, param4?: any, param5?: any) {
        EventMgr.getInstance().emit(listenerName, param1, param2, param3, param4, param5);
    }

    public setUid(uid: number) {
        this.uid = uid;
    }
    public getUid() {
        return this.uid;
    }
    public onOpened() {
        this.isclose = false;
    }
    /**其他界面显示了 当前界面隐藏回调 */
    public onToggleHide(uid: UIID) {

    }
    /**其他界面关闭了 当前界面显示回调 */
    public onToggleShow(uid: UIID) {

    }
    public onStart() { }

    public onClose() {

    }
    protected openUI(uid: UIID, param1?: any, param2?: any, param3?: any, param4?: any, param5?: any) {
        UIMgr.getInstance().openUI(uid, this.uid, param1, param2, param3, param4, param5)
    }
    protected openUICallBack(uid: UIID, callback: Function, param1?: any, param2?: any, param3?: any, param4?: any, param5?: any) {
        UIMgr.getInstance().openUIOfCallback(uid, this.uid, callback, param1, param2, param3, param4, param5)
    }

  
    public closeUI(param1?: any, param2?: any, param3?: any, param4?: any) {
        this.isclose = true;
        this.release();
        UIMgr.getInstance().closeUI(this.node, param1, param2, param3, param4)
    }
    /**不带动画的关闭 */
    protected closeNotAni(param1?: any, param2?: any, param3?: any, param4?: any) {
        this.openAniType = OpenAin.None
        
        this.closeUI(param1, param2, param3, param4)
    }

    private addRes(bundle: string, path: string, type: typeof Asset) {
        if (!this.resArray) return
        let existId = ResCacheMgr.getInstance().isExistKey(bundle + "/" + path, type.name, this.resArray);
        if (existId != -1) {
            if (!this.resArray[existId].defCount) this.resArray[existId].defCount = 0
            this.resArray[existId].defCount++;
        } else {
            let obj = new ResCacheKey(bundle, path, type);
            this.resArray.push(obj)
        }

    }
    /**翻译 */
    protected T(string: string): string {
        return string;
    }
    private release() {
        //释放动态加载的资源
        if (!this.cache && this.resArray) {
            ResCacheMgr.getInstance().refreshTime(this.resArray)
            this.resArray = []
        }
        //去除监听的事件
        if (this.eventList && this.eventList.length > 0) {
            for (let i = 0; i < this.eventList.length; i++) {
                let event = this.eventList[i]
                event.forEach((fun: Function, name: string) => {
                    EventMgr.getInstance().off(name, this, fun);
                })
            }
        }
    }
    public onOpen() { }
    /**带动画打开 uimgr里调用 */
    public openAni(cb?: Function) {
        if (this.openAniType == OpenAin.Pop) {
            this.node.active = true;
            this.node.getComponent(UITransform).priority = this.openAniType===OpenAin.Pop?this.layer+100:this.layer;
            let bg = this.node.getChildByName("bg")
            if (bg.getComponent(UIOpacityComponent)) {
                bg.getComponent(UIOpacityComponent).opacity = 0;
                tween(bg.getComponent(UIOpacityComponent)).to(0.2, { opacity: 200 }).start();
            }
            let root = this.node.getChildByName("root")
            if (root) {
                let orginScale = root.scale;
                root.scale = v3(0);
                let popAni = TweenMgr.getInstance().getTween(root)
                TweenMgr.getInstance().popOpenAin(popAni, () => {
                    if (root.scale != orginScale) {
                        tween(root).to(0.15, { scale: orginScale }).start();
                    }
                    this.onOpen();
                    if (cb) {
                        cb();
                    }
                })
            } else {
                this.node.active = true;
                this.onOpen();
                if (cb) {
                    cb();
                }
            }
        }
    }
    /**带动画关闭  uimgr里调用*/
    public closeAni(callback?: Function) {
        if (this.openAniType == OpenAin.None) {
            callback();
        } else {
            if (this.openAniType == OpenAin.Pop) {
                let bg = this.node.getChildByName("bg")
                if (bg.getComponent(UIOpacityComponent)) {
                    bg.getComponent(UIOpacityComponent).opacity = 200;
                    tween(bg.getComponent(UIOpacityComponent)).to(0.4, { opacity: 0 }).start();
                }
                let root = this.node.getChildByName("root")
                if (root) {
                    let popAni = TweenMgr.getInstance().getTween(root)
                    TweenMgr.getInstance().popCloseAin(popAni, () => {
                        if (callback) {
                            callback();
                        }
                    })
                } else {
                    if (callback) {
                        callback();
                    }
                }
            }
        }
    }
    /**
     * 加载图片 界面关闭后自动释放 
     * @param bundleName bundle名称
     * @param path       路径
     * @param callback   回调
     * @param autoRelese 界面关闭后自动释放资源,默认为true 
     * @param cacheTime 缓存时间,默认10秒
     *  @param saveKey 缓存集合Key 添加到待释放资源Map中，以便调用ResCacheMgr的releaseAssetsFromMap手动释放资源
     */
    protected loadSpriteFrame(bundleName: string, path: string, callback: CompleteCallback);
    protected loadSpriteFrame(bundleName: string, path: string, callback: CompleteCallback, saveKey: string);
    protected loadSpriteFrame(bundleName: string, path: string, callback: CompleteCallback, autoRelese: boolean, cacheTme: number);
    protected loadSpriteFrame(bundleName: string, path: string, callback: CompleteCallback, autoRelese: boolean, cacheTme: number, saveKey: string);
    protected loadSpriteFrame() {
        let args: LoadSpriteFrameArgs = ArgsParseUtils._makeloadSpriteFrameResrgs.apply(this, arguments);
        let bundleName: string = args.bundle
        let path: string = args.path
        let callback: CompleteCallback = args.callback
        let autoRelease: boolean = true
        let saveKey: string = args.saveKey
        ResourceMgr.getInstance().loadSpriteframe(bundleName, path, (res: SpriteFrame) => {
            if (autoRelease) {
                this.addRes(bundleName, path, SpriteFrame)
            }
            if (this.isclose) {
                return;
            }

            callback(res)
        }, autoRelease, args.cacheTme, saveKey)
    }
    /**
   * 从resources文件夹下获取资源
   * @param path 资源路径
   * @param callback 
   */
    public loadFromRes(path: string, type: typeof Asset, callback: CompleteCallback) {
        ResourceMgr.getInstance().loadFromRes(path, type, (res: Asset) => {
            this.addRes("", path, type)
            if (this.isclose) {
                return;
            }
            callback(res)
        })
    }
    /**
       * 从指定的assets bundle加载资源 
       * @param bundleName assets bundle的名称
       * @param path 路径
       * @param type 类型 填Assets子类
       * @param callback 回调
       * @param autoRelese 界面关闭后自动释放资源,默认为true 
       * @param cacheTme 缓存时间,默认10秒
       * @param saveKey 缓存集合Key 添加到待释放资源Map中，以便调用ResCacheMgr的releaseAssetsFromMap手动释放资源
       */
    protected loadResFromBundle(bundleName: string, path: string, type: typeof Asset, callback: CompleteCallback): void;
    protected loadResFromBundle(bundleName: string, path: string, type: typeof Asset, callback: CompleteCallback, saveKey: string): void;
    protected loadResFromBundle(bundleName: string, path: string, type: typeof Asset, callback: CompleteCallback, autoRelese: boolean, cacheTme: number): void;
    protected loadResFromBundle(bundleName: string, path: string, type: typeof Asset, callback: CompleteCallback, autoRelese: boolean, cacheTme: number, saveKey: string): void;
    protected loadResFromBundle() {
        let args: LoadResArgs = ArgsParseUtils._makeLoadResArgs.apply(this, arguments);
        let bundleName: string = args.bundle
        let path: string = args.path
        let callback: CompleteCallback = args.callback
        let autoRelease: boolean = true
        let type: typeof Asset = args.type
        ResourceMgr.getInstance().loadRes(bundleName, path, type, (res: typeof type) => {
            if (autoRelease) {
                this.addRes(bundleName, path, type)
            }
            if (this.isclose) {
                return;
            }
            callback(res)
        }, autoRelease, args.cacheTme, args.saveKey)
    }

    /**
         * 加载纹理 界面关闭后自动释放 
         * @param bundleName assets bundle的名称
         * @param path 
         * @param callback 
         * @param autoRelese 界面关闭后自动释放资源  默认为true 
         */
    protected loadTexture2D(bundleName: string, path: string, callback: CompleteCallback, autoRelese: boolean = true, cacheTime: number = 10) {
        ResourceMgr.getInstance().loadRes(bundleName, path, Texture2D, (res: Texture2D) => {
            if (autoRelese) {
                this.addRes(bundleName, path, Texture2D)
            }
            if (this.isclose) {
                return;
            }

            callback(res)
        }, autoRelese, cacheTime)
    }
    /**
    * 加载预制体 界面关闭后自动释放 
    * @param bundleName assets bundle的名称
    * @param path 
    * @param callback 
    * @param autoRelese 界面关闭后自动释放资源  默认为true 
    */
    protected loadPrefab(bundleName: string, path: string, callback: CompleteCallback, autoRelese: boolean = true, cacheTime: number = 10) {
        ResourceMgr.getInstance().loadRes(bundleName, path, Prefab, (res: Prefab) => {
            if (autoRelese) {
                this.addRes(bundleName, path, Prefab)
            }
            if (this.isclose) {
                return;
            }

            callback(res)
        }, autoRelese, cacheTime)
    }
    /**
    * 加载远程图片
    * @param url   图片URL 小游戏需要在后台添加URL域名白名单
    * @param callback  
    * @param autoRelese 关闭界面后是否自动释放 默认false
    * @param cacheTme   缓存时间
    * @returns 
    */
    protected loadRemoteSpriteFrame(url: string, callback: CompleteCallback, autoRelese: boolean = true, cacheTime: number = 10) {
       
        if(url==""||url==null||url==undefined){
            callback(null)
            return;
        }
        ResourceMgr.getInstance().loadRemoteSpriteFrame(url, (res: SpriteFrame) => {
            if (autoRelese) {
                this.addRes('', url, SpriteFrame)
            }
            if (this.isclose) {
                return;
            }
            callback(res)
        }, autoRelese, cacheTime)
    }
    onDestroy() {
        this.isclose = true;
        this.release();
    }
}